package BlockingQueue;
/**
 * 模拟 定时器工具Timer
 * 相当于 定闹钟 来执行任务
 */

import java.util.Comparator;
import java.util.Timer;
import java.util.concurrent.PriorityBlockingQueue;


public class Demo2 {
    /**
     * 任务类
     */
    static class Task implements Comparable<Task>{
        //任务
        private Runnable task;
        //开始执行的时间
        private long time;

        public Task(Runnable task, long time) {
            this.task = task;
            //time记录开始执行时间
            this.time = time+System.currentTimeMillis();
        }

        //执行任务
        public void run(){
            task.run();
        }

       //优先级堵塞队列需要的比较方法
        @Override
        public int compareTo(Task o) {
            return (int)(this.time-o.time);
        }
    }

    /**
     * 定时器类
     * 循环查看队头元素的任务是否到了执行时间
     */
    static class Timer{
        //优先级阻塞队列
        PriorityBlockingQueue<Task> priorityBlockingQueue=new PriorityBlockingQueue<>();

        //锁
        Object locker=new Object();

        //把任务插入到计时器类
        public void put(Task task){
            synchronized (locker){
                priorityBlockingQueue.put(task);
                /**
                 * 插入元素时唤醒线程
                 * 看看队头元素是否到了执行时间
                 */
                locker.notify();
            }

        }

        public Timer() {
            //线程
            Thread thread=new Thread(()->{
                //循环判断--队头元素是否到了执行时间
                while(true){
                    //每次看看队头元素是否到了执行时间
                    try {
                        //取出队头元素（出队）
                        Task task = priorityBlockingQueue.take();
                        //没有到执行时间
                        if(task.time>System.currentTimeMillis()){
                            //把队头元素重新入队
                            priorityBlockingQueue.put(task);
                            /**
                             * 若还有很长时间才到时间，程序却一直循环检查，就是做无用功
                             * 解决：wait(时间差)
                             * 不用sleep(时间)的原因：wait可以提前唤醒
                             * 提前唤醒：当新插入一个任务时，唤醒
                             */
                            synchronized (locker){
                                locker.wait(task.time-System.currentTimeMillis());
                            }

                        //到执行时间---执行
                        }else{
                            task.run();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }


                }
            });

            thread.start();

        }
    }

    public static void main(String[] args) {
        Timer timer=new Timer();
        timer.put(new Task(()-> System.out.println("hello"),100));
        timer.put(new Task(()-> System.out.println("welcome"),2000));
        timer.put(new Task(()-> System.out.println("to"),3000));
        timer.put(new Task(()-> System.out.println("here"),4000));
        timer.put(new Task(()-> System.out.println("~"),4900));
        timer.put(new Task(()-> System.out.println("everyone"),1500));



    }
}
